function [deblurred_frames_bin] = frame_extract_video_deblur (file)
% Create a video_reader object
video_reader_object = VideoReader(file);
% Create a video_writer object to construct reversed video
deblurred_video = VideoWriter('chambered_nautilus_deblurred.avi', 'Uncompressed AVI');
% Create a folder to store the frames if not already constructed
extracted_frames_folder = 'FRAMES FOLDER';
if ~exist(extracted_frames_folder, 'dir')
mkdir(extracted_frames_folder);
% Get information about the video
num_frames = video_reader_object.NumFrames;
% Dictionary to hold deblurred frames
deblurred_frames_bin = {};
% Make a Wiener deconvolution filter to deblur each frame
PSF_kernel = 15; % Point spread function (PSF) kernel determined by trial and error
noise_level_estimate = 0.1; % Estimated noise level
wiener_filter = fspecial('gaussian', [PSF_kernel, PSF_kernel], noise_level_estimate);
% --- 1.) Read and deblur each frame
% --- 2.) Save each current deblurred frame as a JPEG image into 'FRAMES FOLDER'
% --- 3.) Save each current deblurred frame to deblurred frames bin
% --- 4.) Write each current deblurred frame to deblurred video
% Loop through each frame
for frame_index = 1:num_frames
% --- 1.) Read and deblur each frame
current_blurred_frame = read(video_reader_object, frame_index);
% Deblur each frame using Wiener deconvolution
% Given (true image detail) [convolved with] (PSF) = (blurred image), to recover the
% true image detail use (true image detail) = (blurred image) [deconvolved with] (PSF)
current_deblurred_frame = deconvwnr(current_blurred_frame, wiener_filter, noise_level_estimate);
% --- 2.) Save each current deblurred frame as a JPEG image into 'FRAMES FOLDER'
% At about 30 fps with a 10 second .mp4 clip, about 300 frames of .jpeg
% images should result in the FRAMES FOLDER
current_deblurred_frame_name = sprintf('frame_%04d.jpeg', frame_index);
imwrite(current_deblurred_frame, fullfile(extracted_frames_folder, current_deblurred_frame_name));
% --- 3.) Save each current deblurred frame to deblurred frames bin
% At about 30 fps with a 10 second .mp4 clip, about 300 deblurred
% frames should result in the "deblurred_frames_bin"
deblurred_frames_bin{frame_index} = current_deblurred_frame;
% --- 4.) Write each current deblurred frame to deblurred video
writeVideo(deblurred_video, deblurred_frames_bin{frame_index});
% Close the deblurred video
disp(['Deblurred frames are saved in the folder: ' extracted_frames_folder]);
disp(["Deblurred frames are in workspace as 'deblurred_frames_bin'" ]);
disp(['The deblurred .avi clip is in current working folder']);
function [tinted_frames_bin] = colored_video_maker (color_multipliers, frames_bin)
% Dictionary to hold tinted frames
red_mult = color_multipliers(1);
green_mult = color_multipliers(2);
blue_mult = color_multipliers(3);
% Write frames in order to the video
for frame_index = 1:1:numel(frames_bin)
% Extract the red, green, and blue channels
red_channel = frames_bin{frame_index}(:, :, 1);
green_channel = frames_bin{frame_index}(:, :, 2);
blue_channel = frames_bin{frame_index}(:, :, 3);
tinted_frame = cat(3, red_mult * red_channel, green_mult * green_channel, blue_mult * blue_channel);
% add tinted frame to tinted_frames_bin
tinted_frames_bin{frame_index} = tinted_frame;
function [windowed_frames_bin] = window_adder (frames_bin)
% Dictionary to hold windowed frames
windowed_frames_bin = {};
% Write frames in order to the video
for frame_index = 1:1:numel(frames_bin)
% Define the cross width (1/25th of the image width)
cross_width = round(size(frames_bin{frame_index}, 2) / 25);
% Get the size of the original image
[height, width, ~] = size(frames_bin{frame_index});
% Create a new image as a copy of the original
image_with_cross = frames_bin{frame_index};
% Define the central region for the cross
center_X = round(width / 2);
center_Y = round(height / 2);
% Add horizontal black line
image_with_cross(center_Y - round(cross_width/2) : center_Y + round(cross_width/2), :, 1:3) = 0;
% Add vertical black line
image_with_cross(:, center_X - round(cross_width/2) : center_X + round(cross_width/2), 1:3) = 0;
% Define the border width (1/10th of the image width)
border_width = round(size(image_with_cross, 2) / 10);
% Create a new image with a black border
image_with_border = uint8(zeros(size(image_with_cross, 1) + 2 * border_width, size(image_with_cross, 2) + 2 * border_width, size(image_with_cross, 3)));
% Add horizontal black line
image_with_cross(center_Y - round(cross_width/2) : center_Y + round(cross_width/2), :, 1:3) = 0;
% Add vertical black line
image_with_cross(:, center_X - round(cross_width/2) : center_X + round(cross_width/2), 1:3) = 0;
% Copy the original image into the center of the new image
image_with_border(border_width + 1:end - border_width, border_width + 1:end - border_width, :) = image_with_cross;
% add windowed frame to windowed_frames_bin
windowed_frames_bin{frame_index} = image_with_border;
function [flipped_frames_bin] = left_right_video_flipper (frames_bin)
% Dictionary to hold flipped frames
% Write frames in reverse order to the reversed video
for frame_index = 1:1:numel(frames_bin)
flipped_frame = fliplr(frames_bin{frame_index});
% add flipped frame to flipped_frames_bin
flipped_frames_bin{frame_index} = flipped_frame;
function [reversed_frames_bin] = video_reverser (frames_bin)
% Dictionary to hold flipped frames
reversed_frames_bin = {};
% Write frames in reverse order to the reversed video
for falling_frame_index = numel(frames_bin):-1:1
% add reversed order frame to reverse_frames_bin
reversed_frames_bin{rising_frame_index} = frames_bin{falling_frame_index};
rising_frame_index = rising_frame_index + 1;
function [final_frames, name_string] = video_mash_up (mash_code, input_frames)
intermediate_frames_1 = {}; % Empty all dictionaries at start of each function call
intermediate_frames_2 = {};
intermediate_frames_3 = {};
intermediate_frames_4 = {};
intermediate_frames_5 = {};
intermediate_frames_6 = {};
intermediate_frames_7 = {};
intermediate_frames_8 = {};
intermediate_frames_1 = input_frames;
intermediate_frames_2 = colored_video_maker ([1.5, 0, 0], intermediate_frames_1);
name_string = name_string + 'red(+)';
intermediate_frames_2 = intermediate_frames_1;
name_string = name_string + 'red(-)';
intermediate_frames_3 = colored_video_maker ([0, 1.5, 0], intermediate_frames_2);
name_string = name_string + 'grn(+)';
intermediate_frames_3 = intermediate_frames_2;
name_string = name_string + 'grn(-)';
intermediate_frames_4 = colored_video_maker ([0, 0, 1.5], intermediate_frames_3);
name_string = name_string + 'blu(+)';
intermediate_frames_4 = intermediate_frames_3;
name_string = name_string + 'blu(-)';
intermediate_frames_5 = colored_video_maker ([1.5, 0, 1.5], intermediate_frames_4);
name_string = name_string + 'prp(+)';
intermediate_frames_5 = intermediate_frames_4;
name_string = name_string + 'prp(-)';
intermediate_frames_6 = left_right_video_flipper (intermediate_frames_5);
name_string = name_string + 'flp(+)';
intermediate_frames_6 = intermediate_frames_5;
name_string = name_string + 'flp(-)';
intermediate_frames_7 = video_reverser (intermediate_frames_6);
name_string = name_string + 'rev(+)';
intermediate_frames_7 = intermediate_frames_6;
name_string = name_string + 'rev(-)';
intermediate_frames_8 = window_adder (intermediate_frames_7);
name_string = name_string + 'win(+)';
intermediate_frames_8 = intermediate_frames_7;
name_string = name_string + 'win(-)';
final_frames = intermediate_frames_8;
function [] = video_maker_namer (frames_bin, label_string)
% Create a VideoWriter object to construct reversed video
video_object = VideoWriter('chambered_nautilus_'+label_string+'.avi', 'Uncompressed AVI');
% Write frames in reverse order to the reversed video
for frame_index = 1:1:numel(frames_bin)
% add windowed frame to video
writeVideo(video_object, frames_bin{frame_index});
% Close the reversed video
disp(["A new modified .avi clip is now in the working folder"]);
function [] = video_annotate_function(ground_truth, truth_label, video_to_label, output_name, score_cutoff)
% Create a folder to store the frames if not already constructed
extracted_frames_folder = 'OUTPUT';
if ~exist(extracted_frames_folder, 'dir')
mkdir(extracted_frames_folder);
% load ground truth table
truth = selectLabels(ground_truth, truth_label);
% extract training data for detector from truth table
trainingData = objectDetectorTrainingData(truth);
% construct detector using training data
detector = trainACFObjectDetector(trainingData, 'Numstages', 5);
% load input video file to be labeled into video reader
loaded_video = VideoReader(video_to_label);
% create video player object
video_player = vision.DeployableVideoPlayer;
% relative path to output directory folder, "OUTPUT"
% declare output .avi video file and prepare to add video frames to it to build
outputVideo = VideoWriter(fullfile(workingDir, output_name + ".avi"));
outputVideo.FrameRate = loaded_video.FrameRate;
while hasFrame(loaded_video)
% load input video frames one at a time
frame = readFrame(loaded_video);
% use detector and ground truth to locate possible matching objects
[bbox,score] = detect(detector,frame);
% assign probability of match rank to possible matching objects
% retain only those match rank probabilities above score cut off
bbox = bbox(score > score_cutoff,:);
score = score(score > score_cutoff,:);
[selectedBbox,selectedScore] = selectStrongestBbox(bbox,score, OverlapThreshold=0.1);
numBoxes = size(selectedBbox,1);
% annotate possible matching objects
str = "OBJECTS DETECTED : " + numBoxes;
img = insertObjectAnnotation(frame,"rectangle", selectedBbox,truth_label + " : " + selectedScore);
img = insertText(img,[250 550],str,TextColor=[1 1 0]);
% display each annotated video frame in video player object
% write each annotated video frame to declared output .avi video file
writeVideo(outputVideo,img)
disp(["A new annotated .avi clip is now in the folder, 'OUTPUT'"]);